/*
 * Project Name spring-boot-tools
 * File Name AuthInterceptor
 * Package Name com.huxiaosu.tools.common.auth.service
 * Create Time 2024/7/26
 * Create by name：liujie
 */
package com.huxiaosu.tools.common.auth.service;

import com.huxiaosu.tools.common.auth.annotation.NoAuth;
import com.huxiaosu.tools.common.auth.confingure.IgnoreProperties;
import com.huxiaosu.tools.common.base.LogonUser;
import com.huxiaosu.tools.common.constant.CommonConst;
import com.huxiaosu.tools.common.holder.LogonUserHolder;
import com.huxiaosu.tools.common.holder.SpringContextHolder;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;
import java.util.*;

/**
 * Description
 *
 * @author liujie
 * @date 2024/7/26 17:30
 */
@Slf4j
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        log.info("request url = {}",request.getRequestURI());
        // step1 过滤 options
        if (request.getMethod().equals(RequestMethod.OPTIONS.name())) {
            return true;
        }
        // step2 过滤 websocket
        String upgrade = request.getHeader("Upgrade");
        if (Objects.nonNull(upgrade) && CommonConst.UPGRADE_WEBSOCKET.equalsIgnoreCase(upgrade)) {
            return true;
        }
        // 填充默认用户 测试用的
        setDefaultUser();
        // 过滤不认证的接口 过滤白名单
        if (isNoAuth(object) || ignorePath(request)) {
            return true;
        }
        checkPerm();
        return true;
    }
    private boolean ignorePath(HttpServletRequest request){
        String uri = request.getRequestURI();
        // 读取白名单配置； 这里可以读取自定义配置 或者使用 shiro
        return matchPath(uri);
    }
    private boolean matchPath(String uri) {
        List<String> pathPatternList = new ArrayList<>();
        IgnoreProperties ignoreProperties = SpringContextHolder.getBean(IgnoreProperties.class);
        if (ignoreProperties.isEnabled()) {
            LinkedHashMap<String, String> linkedHashMap = ignoreProperties.getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : linkedHashMap.entrySet()) {
                String value = entry.getValue();
                if (! StringUtils.hasText(value) || "anon".equalsIgnoreCase(value)) {
                    String[] keys = entry.getKey().split(",");
                    for (String key : keys) {
                        if (StringUtils.hasText(key.trim())) {
                            pathPatternList.add(key.trim());
                        }
                    }
                }
            }
        }

        AntPathMatcher antPathMatcher = new AntPathMatcher();
        for (String matcher : pathPatternList) {
            if (antPathMatcher.match(matcher, uri)) {
                return true;
            }
        }

        return false;
    }

    private void checkPerm(){
        // 判断用户是不是有权限

    }

    private boolean isNoAuth(Object handler){
        if (!(handler instanceof HandlerMethod)){
            log.warn("isNoAuth warn {}",handler.getClass().getName());
            return true;
        }
        try {
            Class<?> targetClass = ((HandlerMethod) handler).getBean().getClass();
            if (targetClass.getAnnotation(NoAuth.class) != null) {
                return true;
            }

            Method method = ((HandlerMethod) handler).getMethod();
            if (method.getAnnotation(NoAuth.class) != null) {
                return true;
            }
        } catch (Exception e) {
            log.error("isNoAuth", e);
        }

        return false;
    }

    private void setDefaultUser() {
        LogonUser logonUser = new LogonUser();
        logonUser.setId(1);
        logonUser.setUsername("admin");
        logonUser.setGroupId(Arrays.asList(1,2));
        logonUser.setRoleIds(Arrays.asList(1,2));
        logonUser.setRealName("超级管理员");
        logonUser.setTenantId("000000");
        LogonUserHolder.set(logonUser);
    }
}